#include "server_tools.h"

const uint8 days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

// =========================字符串工具=========================

/* 字符串是否有特定子串
    * 该函数用于判断字符串str中是否包含子字符串sub_str
    * @param str 要查找的字符串
    * @param sub_str 要查找的子字符串
    * @param is_sensitive 是否大小写敏感
    * @return 如果包含返回1，不包含或者异常返回0
*/
uint8 server_string_is_in(wchar_t * str, wchar_t * sub_str, StringIsSensitive is_sensitive) {
    if (str == NULL || sub_str == NULL) {
        server_log(LOG_SYSTEM, "Null string passed to server_string_is_in.");
        return 0; // 如果字符串或子字符串为NULL，返回0
    }
    if (wcslen(str) == 0 || wcslen(sub_str) == 0) {
        server_log(LOG_SYSTEM, "Empty string or substring passed to server_string_is_in.");
        return 0; // 如果字符串或子字符串为空，直接返回0
    }
    if (is_sensitive == STRING_CASE_SENSITIVE) {
        // 大小写敏感比较
        return wcsstr(str, sub_str) != NULL; // 使用wcsstr进行宽字符子字符串查找
    } else {
        if (str == NULL || sub_str == NULL) {
            // 内存分配失败
            server_log(LOG_SYSTEM, "Memory allocation failed in server_string_is_in.");
            return 0;
        }
        // 转换为小写
        for (wchar_t * p = str; *p; ++p) *p = towlower(*p);
        for (wchar_t * p = sub_str; *p; ++p) *p = towlower(*p);
        // 查找子字符串
        uint8 result = wcsstr(str, sub_str) != NULL;
        return result;
    }
}

// =========================日期工具=========================

/* 判断是否为闰年
    * 该函数用于判断给定年份是否为闰年
    * @param year 要判断的年份
    * @return 如果是闰年返回1，否则返回0
*/
uint8   is_leap_year(uint16 year){
    if (year < 1582) {
        server_log(LOG_SYSTEM, "Year %d is before the Gregorian calendar was adopted.", year);
        return 0; // 1582年之前的年份不考虑闰年
    }
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
        return 1; // 能被4整除但不能被100整除的是闰年
    }
    return 0; // 不是闰年
}

/* 获取指定月份的天数
    * 该函数用于获取指定年份和月份的天数
    * @param year 要查询的年份
    * @param month 要查询的月份
    * @return 指定月份的天数
*/
uint8   get_days_in_month(uint16 year, uint8 month){
    if (month < 1 || month > 12) {
        server_log(LOG_SYSTEM, "Invalid month %d", month);
        server_assert(month < 1 || month > 12); // 重大错误，断言
        return 0; // 如果月份不在1到12之间，返回0
    }
    
    if (month == 2 && is_leap_year(year)) {
        return 29; // 闰年2月有29天
    }
    return days_in_month[month - 1]; // 返回对应月份的天数
}

/* 将日期转换为天数
    * 该函数用于将给定的日期转换为从公元1年1月1日开始的天数
    * @param date 要转换的日期
    * @return 从公元1年1月1日开始的天数
*/
uint32  date_to_days(ServerDate * date){
    if (date == NULL) {
        server_log(LOG_SYSTEM, "Null date pointer passed to date_to_days.");
        return 0; // 如果日期指针为NULL，返回0
    }
    uint32 days = 0;
    for (uint16 i = 1; i < date->year; i++) {
        days += is_leap_year(i) ? 366 : 365;
    }
    // 加上当前月份的天数
    for (uint8 i = 1; i < date->month; i++) {
        days += get_days_in_month(date->year, i);
    }
    days += date->day; // 加上当前月的天数

    return days;
}

/* 获取当前日期
    * 该函数用于获取当前系统日期并存储到ServerDate结构体中
    * @param date 存储当前日期的ServerDate结构体指针
*/
void    server_get_current_date(ServerDate * date){
    if (date == NULL) {
        server_log(LOG_SYSTEM, "Null date pointer passed to server_get_current_date.");
        server_assert(date == NULL); // 重大错误，断言
        return; // 如果日期指针为NULL，直接返回
    }
    time_t current_time_s;
    time(&current_time_s);
    struct tm * current_time = localtime(&current_time_s);
    if (current_time == NULL) {
        server_log(LOG_SYSTEM, "Failed to get current time.");
        server_assert(current_time == NULL); // 重大错误，断言
        return; // 如果获取当前时间失败，直接返回
    }
    date->year  = current_time->tm_year + 1900; // tm_year从1900年开始计算
    date->month = current_time->tm_mon + 1;     // tm_mon从0开始计算
    date->day   = current_time->tm_mday;        // tm_mday是当前月的第几天
}

/* 计算两个日期之间的天数差
    * 该函数用于计算两个ServerDate结构体表示的日期之间的天数差
    * @param date_from 起始日期
    * @param date_to 结束日期
    * @return 两个日期之间的天数差，如果date_from大于date_to则返回负值
*/
uint32  server_calc_date_difference(ServerDate * date_from, ServerDate * date_to) {
    if (date_from == NULL || date_to == NULL) {
        server_log(LOG_SYSTEM, "Null date pointer passed to server_calc_date_difference.");
        // 断言
        server_assert(date_from == NULL || date_to == NULL); // 重大错误，断言
        return 0; // 如果日期指针为NULL，返回0
    }

    uint32 days_from = date_to_days(date_from);
    uint32 days_to   = date_to_days(date_to);
    return days_to - days_from;
}
